package com.icesoft.generation.helper;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.Column;
import com.icesoft.framework.core.annotation.Entity;
import com.icesoft.framework.core.binding.annotation.*;
import com.icesoft.generation.vo.GenDtoFieldVO;
import com.icesoft.generation.vo.GenFieldVO;
import com.icesoft.generation.vo.GenTableVO;
import com.icesoft.generation.vo.GenVoFieldVO;
import org.reflections.Reflections;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.text.Collator;
import java.util.*;

public class TableJavaFileHelper {

	public static List<GenTableVO> getTables() {
		Reflections reflections = new Reflections("com.icesoft");
		Set<Class<?>> set = reflections.getTypesAnnotatedWith(Entity.class, true);
		TreeSet<Class<?>> treeSet = new TreeSet<>((class1, class2) -> {
			Collator comparator = Collator.getInstance(Locale.CHINA);
			return comparator.compare(class2.getSimpleName(), class1.getSimpleName());
		});

		treeSet.addAll(set);
		List<GenTableVO> genTableList = new ArrayList<>();
		for (Class<?> entityClass : treeSet) {
			Entity entity = entityClass.getAnnotation(Entity.class);
			TableName tableName = entityClass.getAnnotation(TableName.class);
			if (tableName == null) {
				continue;
			}

			String packageName = entityClass.getName().replace("." + entityClass.getSimpleName(), "").replace(".entity", "");
			String dtoPackage = packageName + ".dto." + entityClass.getSimpleName() + "DTO";
			String voPackage = packageName + ".vo." + entityClass.getSimpleName() + "VO";
			String controllerPackage = packageName + ".controller." + entityClass.getSimpleName() + "Controller";

			Class<?> controllerClass = getClass(controllerPackage);

			GenTableVO genTable = new GenTableVO();
			genTable.setPackageName(packageName);
			genTable.setTableName(tableName.value());
			genTable.setTableComment(entity.describe());
			genTable.setModuleName(entity.module());
			genTable.setClassName(entityClass.getSimpleName());

			if (controllerClass != null) {
				RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class);
				genTable.setRequestMapping(requestMapping.value()[0]);
			}
			genTable.setFields(getFields(entityClass));

			Class<?> dtolClass = getClass(dtoPackage);
			if (dtolClass != null) {
				genTable.setDtoFields(getDTOFields(dtolClass));
			}
			Class<?> voClass = getClass(voPackage);
			if (voClass != null) {
				genTable.setVoFields(getVOFields(voClass));
			}
			genTableList.add(genTable);
		}
		return genTableList;
	}

	public static List<GenFieldVO> getFields(Class<?> entityClass) {
		List<GenFieldVO> entityFieldList = new ArrayList<>();
		Field[] fields = entityClass.getDeclaredFields();

		for (Field field : fields) {
			TableField tableField = field.getAnnotation(TableField.class);
			if (tableField != null) {
				Column column = field.getAnnotation(Column.class);
				String typeName = field.getGenericType().getTypeName();
				String name = field.getName();

				GenFieldVO entityField = new GenFieldVO();
				entityField.setType(typeName);
				entityField.setName(name);
				entityField.setExist(tableField.exist());
				if (column != null) {
					entityField.setCommentType(column.type().name());
					entityField.setCommentComment(column.comment());
					entityField.setCommentName(column.value());
				}
				entityFieldList.add(entityField);
			}
		}
		return entityFieldList;
	}

	public static List<GenDtoFieldVO> getDTOFields(Class<?> dtoClass) {
		return null;
	}

	public static List<GenVoFieldVO> getVOFields(Class<?> voClass) {
		List<GenVoFieldVO> genFieldVos = new ArrayList<>();
		Field[] fields = voClass.getDeclaredFields();
		for (Field field : fields) {
			String typeName = field.getGenericType().getTypeName();
			String name = field.getName();
			GenVoFieldVO voField = new GenVoFieldVO();
			voField.setType(typeName);
			voField.setName(name);
			Annotation[] annotations = field.getAnnotations();
			if (annotations != null && annotations.length > 0) {
				Annotation annotation = annotations[0];
				String bindName = annotation.annotationType().getSimpleName();
				if (bindName.equals("BindField")) {
					BindField bindField = field.getAnnotation(BindField.class);
					voField.setBindName("BindField");
					voField.setBind(annotation.annotationType().getName());
					voField.setEntityClass(bindField.entity().getName());
					voField.setEntity(bindField.entity().getSimpleName());
					voField.setConditionValue(bindField.condition());
					voField.setField(bindField.field());
				}
				if (bindName.equals("BindFieldList")) {
					BindFieldList bindField = field.getAnnotation(BindFieldList.class);
					voField.setBindName("BindFieldList");
					voField.setBind(annotation.annotationType().getName());
					voField.setEntityClass(bindField.entity().getName());
					voField.setEntity(bindField.entity().getSimpleName());
					voField.setConditionValue(bindField.condition());
					voField.setField(bindField.field());
				}
				if (bindName.equals("BindEntity")) {
					BindEntity bindField = field.getAnnotation(BindEntity.class);
					voField.setBindName("BindEntity");
					voField.setBind(annotation.annotationType().getName());
					voField.setEntityClass(bindField.entity().getName());
					voField.setEntity(bindField.entity().getSimpleName());
					voField.setConditionValue(bindField.condition());
				}
				if (bindName.equals("BindEntityList")) {
					BindEntityList bindField = field.getAnnotation(BindEntityList.class);
					voField.setBindName("BindEntityList");
					voField.setBind(annotation.annotationType().getName());
					voField.setEntityClass(bindField.entity().getName());
					voField.setEntity(bindField.entity().getSimpleName());
					voField.setConditionValue(bindField.condition());
				}
				if (bindName.equals("BindDict")) {
					BindDict bindField = field.getAnnotation(BindDict.class);
					voField.setBindName("BindDict");
					voField.setBind(annotation.annotationType().getName());
					voField.setEntity(bindField.type());
				}
			}

			genFieldVos.add(voField);
		}
		return genFieldVos;
	}

	private static Class<?> getClass(String name) {
		try {
			return Class.forName(name);
		} catch (ClassNotFoundException e) {
			return null;
		}
	}
}
